import { isFunction, isPlainObject } from './utils'
import { ComponentLifecycle, createLifecycleMethods } from './lifecycle'
import { wrapFuns, deepToRaw } from './shared'
import { createContext, IContext } from './context'
import { setCurrentInstance, ComponentInstance } from './instance'
import { reactive } from './reactive'

type Setup<Porps extends Object> = (props: Porps, context: IContext) => Record<string, any>
type ComponentSetup = Setup<Record<string, any>>
type ComponentOptions = WechatMiniprogram.Component.Options<
    Record<string, any>,
    Record<string, WechatMiniprogram.Component.AllProperty>,
    Record<string, (...args: any[]) => any>
>

/** 
 * 页面入口方法
 * @param setup {ComponentSetup} setup方法
 */
export function VComponent(
    options: ComponentSetup | ({ setup?: ComponentSetup } & ComponentOptions)
): string {
    let setupFn: ComponentSetup // setup函数
    let miniOptions: Record<string, any> = {} // 小程序Component原本的参数
    if (isFunction(options)) {
        // options为函数，则options为setup函数
        setupFn = options
    } else {
        if (options.setup === undefined) {
            // 如果options没有setup函数，则直接执行小程序Component方法
            return Component(options)
        }
        let { setup: setupFunc, ...otherOptions } = options
        setupFn = setupFunc
        miniOptions = otherOptions
    }

    // lifetimes
    miniOptions.lifetimes = miniOptions.lifetimes || {}
    for (let key in ComponentLifecycle) {
        if (
            !miniOptions.lifetimes[ComponentLifecycle[key]]
            && miniOptions[ComponentLifecycle[key]]
        ) {
            miniOptions.lifetimes[ComponentLifecycle[key]] = miniOptions[ComponentLifecycle[key]]
        }
    }

    // onAttached生命周期
    miniOptions.lifetimes[ComponentLifecycle.ATTACHED] =
        wrapFuns(function (this: ComponentInstance) {
            setCurrentInstance(this); // 保存Component实例，供给setup中的生命周期使用
            let context = createContext.call(this) // VComponent创建实例，并绑定Component实例
            let SetupTask: Record<string, any> = setupFn.call(this, reactive(deepToRaw(this.properties)), context) // 执行setup方法
            if (!isPlainObject(SetupTask)) console.error('setup返回格式错误')
            context.setData(SetupTask) // 将setup返回数据插入Component实例中
            setCurrentInstance(null); // 清空储存的pComponent实例
        }, createLifecycleMethods(ComponentLifecycle.ATTACHED, miniOptions.lifetimes))

    // 其他生命周期
    for (let key in ComponentLifecycle) {
        switch (ComponentLifecycle[key]) {
            case ComponentLifecycle.ATTACHED:
                break;
            default:
                miniOptions.lifetimes[ComponentLifecycle[key]] =
                    createLifecycleMethods(ComponentLifecycle[key], miniOptions.lifetimes)
                break;
        }
    }

    return Component(miniOptions)
}